/
[slug].astro
executable file
·135 lines (124 loc) · 3.7 KB
/
[slug].astro
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
---
import * as interfaces from '../../lib/interfaces.ts'
import {
getPosts,
getAllPosts,
getRankedPosts,
getPostBySlug,
getPostsByTag,
getBlock,
getAllTags,
getAllBlocksByBlockId,
downloadFile,
} from '../../lib/notion/client.ts'
import {
getPostLink,
filePath,
extractTargetBlocks,
} from '../../lib/blog-helpers.ts'
import Layout from '../../layouts/Layout.astro'
import PostDate from '../../components/PostDate.astro'
import PostTags from '../../components/PostTags.astro'
import PostTitle from '../../components/PostTitle.astro'
import PostBody from '../../components/PostBody.astro'
import PostRelativeLink from '../../components/PostRelativeLink.astro'
import BlogPostsLink from '../../components/BlogPostsLink.astro'
import BlogTagsLink from '../../components/BlogTagsLink.astro'
import styles from '../../styles/blog.module.css'
export async function getStaticPaths() {
const posts = await getAllPosts()
return posts.map((post: interfaces.Post) => ({ params: { slug: post.Slug } }))
}
const { slug } = Astro.params
const post = await getPostBySlug(slug)
if (!post) {
throw new Error('Post not found. slug: ${slug}')
}
const [blocks, allPosts, rankedPosts, recentPosts, tags, postsHavingSameTag] =
await Promise.all([
getAllBlocksByBlockId(post.PageId),
getAllPosts(),
getRankedPosts(),
getPosts(5),
getAllTags(),
getPostsByTag(post.Tags[0]?.name, 6),
])
const fileAtacchedBlocks = extractTargetBlocks('image', blocks)
.concat(extractTargetBlocks('file', blocks))
.filter((block) => {
if (!block) {
return false
}
const imageOrFile = block.Image || block.File
return imageOrFile && imageOrFile.File && imageOrFile.File.Url
})
// Download files
await Promise.all(
fileAtacchedBlocks
.map(async (block) => {
const expiryTime = (block.Image || block.File).File.ExpiryTime
if (Date.parse(expiryTime) > Date.now()) {
return Promise.resolve(block)
}
return getBlock(block.Id)
})
.map((promise) =>
promise.then((block) => {
let url!: URL
try {
url = new URL((block.Image || block.File).File.Url)
} catch (err) {
console.log('Invalid file URL')
return Promise.reject()
}
return Promise.resolve(url)
})
)
.map((promise) => promise.then(downloadFile))
)
const currentPostIndex = allPosts.findIndex((post) => post.Slug === slug)
const prevPost = allPosts[currentPostIndex + 1]
const nextPost = allPosts[currentPostIndex - 1]
let ogImage = ''
if (post.FeaturedImage && post.FeaturedImage.Url) {
ogImage = new URL(filePath(new URL(post.FeaturedImage.Url)), Astro.site)
}
---
<Layout
title={post.Title}
description={post.Excerpt}
path={getPostLink(post.Slug)}
ogImage={ogImage}
openGraph={{
basic: {
title: post.Title,
type: 'article',
image: new URL(`/og/${post.Slug}.png`, Astro.url.origin).toString(),
},
image: { alt: post.Title },
}}
>
<div slot="main" class={styles.main}>
<div class={styles.post}>
<PostDate post={post} />
<PostTags post={post} />
<PostTitle post={post} enableLink={false} />
<PostBody blocks={blocks} />
<PostTags post={post} />
<footer>
<PostRelativeLink prevPost={prevPost} nextPost={nextPost} />
</footer>
</div>
</div>
<div slot="aside" class="aside">
<BlogPostsLink
heading="Posts in the same category"
posts={postsHavingSameTag.filter(
(p: interfaces.Post) => p.Slug !== post.Slug
)}
/>
<BlogPostsLink heading="Recommended" posts={rankedPosts} />
<BlogPostsLink heading="Latest posts" posts={recentPosts} />
<BlogTagsLink heading="Categories" tags={tags} />
</div>
</Layout>